import React, { useState, useEffect, useRef, useCallback } from 'react'; import { initializeApp } from 'firebase/app'; import { getAuth, signInAnonymously, signInWithCustomToken, onAuthStateChanged } from 'firebase/auth'; import { getFirestore, doc, setDoc, onSnapshot, collection, query, serverTimestamp, deleteDoc, updateDoc, FieldValue, getDoc } from 'firebase/firestore'; // Tone.js is loaded via a script tag in the HTML for global access. // Example: const App = () => { // Firebase states const [db, setDb] = useState(null); const [auth, setAuth] = useState(null); const [userId, setUserId] = useState(null); const [isAuthReady, setIsAuthReady] = useState(false); // Application-specific states const [currentVisitors, setCurrentVisitors] = useState(0); const [totalVisitorsCount, setTotalVisitorsCount] = useState(0); const [uptime, setUptime] = useState(''); // Nyan Cat GIF management const nyanGifs = useRef([ // Updated GIF URLs for better embedding reliability "https://i.giphy.com/media/sIIh4zF9uJgY/giphy.gif", // Original "https://i.giphy.com/media/RkhTEoD6N5D0W0X9t6/giphy.gif", // Different angle "https://i.giphy.com/media/TTAi42ZfS6A08/giphy.gif", // Pixel art style "https://i.giphy.com/media/wM90d5Sj9gUjK/giphy.gif", // 8-bit style "https://i.giphy.com/media/sSfY2u5MhW5fJzW3/giphy.gif" // Space background ]); const [currentGifIndex, setCurrentGifIndex] = useState(0); // Refs for Tone.js const synthRef = useRef(null); const sequenceRef = useRef(null); const sessionIdRef = useRef(crypto.randomUUID()); // Site launch date const siteLaunchDate = useRef(new Date('2024-06-13T00:00:00Z')); /** * Handles clicking on the Nyan Cat GIF to switch to the next one in the list. */ const handleGifClick = () => { setCurrentGifIndex((prevIndex) => (prevIndex + 1) % nyanGifs.current.length // Cycle through the array ); }; /** * useEffect Hook: Initializes Firebase and handles user authentication. * Runs only once on component mount. */ useEffect(() => { let app, firestore, authentication; try { const appId = typeof __app_id !== 'undefined' ? __app_id : 'default-app-id'; const firebaseConfig = typeof __firebase_config !== 'undefined' ? JSON.parse(__firebase_config) : {}; app = initializeApp(firebaseConfig); firestore = getFirestore(app); authentication = getAuth(app); setDb(firestore); setAuth(authentication); const unsubscribeAuth = onAuthStateChanged(authentication, async (user) => { if (user) { setUserId(user.uid); } else { try { if (typeof __initial_auth_token !== 'undefined' && __initial_auth_token) { await signInWithCustomToken(authentication, __initial_auth_token); } else { await signInAnonymously(authentication); } } catch (error) { console.error("Firebase authentication error:", error); setUserId(crypto.randomUUID()); } } setIsAuthReady(true); }); return () => unsubscribeAuth(); } catch (error) { console.error("Failed to initialize Firebase:", error); setUserId(crypto.randomUUID()); setIsAuthReady(true); } }, []); /** * useEffect Hook: Initializes Tone.js synthesizer and sequence for the Nyan Cat theme. * Runs only once on component mount. */ useEffect(() => { if (typeof window.Tone !== 'undefined' && !synthRef.current) { console.log("Tone.js detected, initializing synthesizer and starting music..."); synthRef.current = new window.Tone.Synth().toDestination(); sequenceRef.current = new window.Tone.Sequence((time, note) => { synthRef.current.triggerAttackRelease(note, "8n", time); }, ["C5", "G4", "E4", "G4", "A4", "G4", "F4", "D4"]).start(0); sequenceRef.current.loop = true; sequenceRef.current.playbackRate = 1.5; window.Tone.Transport.bpm.value = 120; const startAudio = async () => { try { await window.Tone.start(); window.Tone.Transport.start(); console.log("Nyan Cat theme started automatically!"); } catch (e) { console.error("Failed to start Tone.js audio context:", e); } }; startAudio(); } else if (typeof window.Tone === 'undefined') { console.warn("Tone.js (window.Tone) is not yet defined. Music functionality may be delayed or unavailable."); } return () => { if (sequenceRef.current) { sequenceRef.current.dispose(); sequenceRef.current = null; } if (synthRef.current) { synthRef.current.dispose(); synthRef.current = null; } }; }, []); /** * useEffect Hook: Calculates and updates the site's uptime every second. * Runs only once on component mount. */ useEffect(() => { const calculateUptime = () => { const now = new Date(); const diff = now.getTime() - siteLaunchDate.current.getTime(); const seconds = Math.floor(diff / 1000); const minutes = Math.floor(seconds / 60); const hours = Math.floor(minutes / 60); const days = Math.floor(hours / 24); const months = Math.floor(days / 30.44); const years = Math.floor(days / 365.25); const remainingMonths = months % 12; const remainingDays = Math.floor(days % 30.44); const remainingHours = hours % 24; const remainingMinutes = minutes % 60; const remainingSeconds = seconds % 60; let uptimeString = ''; if (years > 0) uptimeString += `${years} year${years !== 1 ? 's' : ''}, `; if (remainingMonths > 0) uptimeString += `${remainingMonths} month${remainingMonths !== 1 ? 's' : ''}, `; if (remainingDays > 0) uptimeString += `${remainingDays} day${remainingDays !== 1 ? 's' : ''}, `; uptimeString += `${remainingHours} hour${remainingHours !== 1 ? 's' : ''}, `; uptimeString += `${remainingMinutes} minute${remainingMinutes !== 1 ? 's' : ''}, `; uptimeString += `${remainingSeconds} second${remainingSeconds !== 1 ? 's' : ''}`; setUptime(uptimeString.trim()); }; const intervalId = setInterval(calculateUptime, 1000); calculateUptime(); return () => clearInterval(intervalId); }, []); /** * useEffect Hook: Handles concurrent and total visitor tracking using Firestore. */ useEffect(() => { if (!db || !isAuthReady || !userId) { console.log("Firestore not ready for visitor logic. Waiting for initialization..."); return; } const appId = typeof __app_id !== 'undefined' ? __app_id : 'default-app-id'; const sessionDocRef = doc(db, `artifacts/${appId}/public/data/activeSessions`, sessionIdRef.current); const globalStatsDocRef = doc(db, `artifacts/${appId}/public/data/siteStats/globalStats`); const countedSessionDocRef = doc(db, `artifacts/${appId}/public/data/countedSessions`, sessionIdRef.current); const initializeTotalVisits = async () => { try { await setDoc(globalStatsDocRef, { totalVisits: 0 }, { merge: true }); } catch (error) { console.error("Error initializing total visits document:", error); } }; const incrementTotalVisits = async () => { try { const sessionCountDoc = await getDoc(countedSessionDocRef); if (!sessionCountDoc.exists()) { await setDoc(countedSessionDocRef, { timestamp: serverTimestamp() }); await updateDoc(globalStatsDocRef, { totalVisits: FieldValue.increment(1) }); console.log("Total visitors count incremented for new session."); } else { console.log("Session already counted for total visitors."); } } catch (error) { console.error("Error incrementing total visitors:", error); } }; initializeTotalVisits(); incrementTotalVisits(); const updateLastActive = async () => { try { await setDoc(sessionDocRef, { lastActive: serverTimestamp(), userId: userId, }, { merge: true }); console.log(`Concurrent session ${sessionIdRef.current} updated in Firestore.`); } catch (error) { console.error("Error updating concurrent session in Firestore:", error); } }; const updateInterval = setInterval(updateLastActive, 5000); updateLastActive(); const sessionsCollectionRef = collection(db, `artifacts/${appId}/public/data/activeSessions`); const unsubscribeConcurrentSnapshot = onSnapshot(sessionsCollectionRef, (snapshot) => { const now = Date.now(); const activeThreshold = 15 * 1000; let count = 0; snapshot.docs.forEach(doc => { const data = doc.data(); if (data.lastActive && typeof data.lastActive.toMillis === 'function') { if (now - data.lastActive.toMillis() < activeThreshold) { count++; } } }); setCurrentVisitors(count); console.log(`Current active visitors: ${count}`); }, (error) => { console.error("Error listening to active sessions:", error); }); const unsubscribeTotalVisitors = onSnapshot(globalStatsDocRef, (docSnap) => { if (docSnap.exists()) { setTotalVisitorsCount(docSnap.data().totalVisits || 0); } else { setTotalVisitorsCount(0); } }, (error) => { console.error("Error listening to total visitors:", error); }); return () => { clearInterval(updateInterval); unsubscribeConcurrentSnapshot(); unsubscribeTotalVisitors(); const deleteSession = async () => { if (db && userId) { try { await deleteDoc(sessionDocRef); console.log(`Concurrent session ${sessionIdRef.current} deleted on unload.`); } catch (error) { console.error("Error deleting concurrent session on unload:", error); } } }; window.addEventListener('beforeunload', deleteSession); return () => { window.removeEventListener('beforeunload', deleteSession); }; }; }, [db, isAuthReady, userId]); // Display a loading message until Firebase authentication is ready. if (!isAuthReady) { return (

Loading Nyan Cat magic...

); } return ( // Main container for the app, styled with Tailwind CSS for responsiveness and aesthetics. // Reverted to the original colorful gradient background.
{/* Content card: holds all main elements - no hover effect */}
{/* Title */}

Welcome to the Nyan-tastic Site!

{/* Nyan Cat GIF */} Nyan Cat { e.target.onerror = null; e.target.src = "https://placehold.co/400x300/e0e0e0/ffffff?text=Nyan+Cat+GIF"; }} /> {/* Concurrent Visitors Count */}

People on the site right meow: {currentVisitors}

{/* Total Visitors Count */}

Total visitors so far: {totalVisitorsCount}

{/* Site Uptime Display */}

Site has been up for:

{uptime}

{/* Credit to Original Creators */}

Inspired by the original Nyan Cat by nyan.cat

{/* User ID display (for debugging/identification in a multi-user environment) */}

Your user ID for this session: {userId || 'N/A'}

); }; export default App;